package mvc_generator.generator.car.struts

import mvc_generator.generator.MVCGeneratorGeneratorUtils
import mvc_generator.mVCGenerator.ArithmeticExpression
import mvc_generator.mVCGenerator.ArithmeticPrimitive
import mvc_generator.mVCGenerator.ArithmeticVariable
import mvc_generator.mVCGenerator.AssignedField
import mvc_generator.mVCGenerator.BooleanExpression
import mvc_generator.mVCGenerator.BooleanPrimitive
import mvc_generator.mVCGenerator.BooleanVariable
import mvc_generator.mVCGenerator.Condition
import mvc_generator.mVCGenerator.Controller
import mvc_generator.mVCGenerator.DoubleExpression
import mvc_generator.mVCGenerator.Expression
import mvc_generator.mVCGenerator.Form
import mvc_generator.mVCGenerator.FormValidation
import mvc_generator.mVCGenerator.IntegerExpression
import mvc_generator.mVCGenerator.ModelMVC
import mvc_generator.mVCGenerator.ParenthesizedArithmeticExpression
import mvc_generator.mVCGenerator.ParenthesizedBooleanExpression
import mvc_generator.mVCGenerator.StringExpression
import mvc_generator.mVCGenerator.StringLengthExpression
import org.eclipse.xtext.generator.IFileSystemAccess

class ValidationFormGenerator {

	StrutsGenerator g; //utile pour lui transmettre les lignes a ecrire 

	//dans le fichier Resources.properties 
	new(StrutsGenerator gen) {
		g = gen;
	}

	def void generate(Form form, IFileSystemAccess fsa) {

		var ModelMVC modelMVCContainer = MVCGeneratorGeneratorUtils.findModelMVCContainer(form);
		var CharSequence validationFormContent = '''''';
		var CharSequence fieldDeclarationContent = '''''';
		var CharSequence getterContent = '''''';
		var CharSequence setterContent = '''''';

		fieldDeclarationContent = '''
			private static final long serialVersionUID = 1L;
				«FOR AssignedField assignedField : form.assignedFields»
					private «MVCGeneratorGeneratorUtils.getSimpleTypeOfAssignement(assignedField).stringRepresentation» «assignedField.
				fieldName» = «MVCGeneratorGeneratorUtils.getInitialValue(
				MVCGeneratorGeneratorUtils.getSimpleTypeOfAssignement(assignedField))»;
				«ENDFOR»
		'''

		getterContent = '''
			«FOR AssignedField assignedField : form.assignedFields»
				/**
				 * @return «assignedField.fieldName»
				 */
				public «MVCGeneratorGeneratorUtils.getSimpleTypeOfAssignement(assignedField).stringRepresentation» get«assignedField.
				fieldName.toFirstUpper»() {
					return «assignedField.fieldName»;
				}
			«ENDFOR»	
		'''

		setterContent = '''
			«FOR AssignedField assignedField : form.assignedFields»
				/**
				 * @param «MVCGeneratorGeneratorUtils.getSimpleTypeOfAssignement(assignedField).stringRepresentation»
				 *            Sets the «assignedField.fieldName»
				 */
				public void set«assignedField.fieldName.toFirstUpper»(«MVCGeneratorGeneratorUtils.
				getSimpleTypeOfAssignement(assignedField).stringRepresentation» value) {
					«assignedField.fieldName» = value»;
				}
			«ENDFOR»	
		'''

		validationFormContent = '''
		package actionForm;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

public class «form.name»ValidationForm extends ActionForm {

	«fieldDeclarationContent»
	«getterContent»
	
	«setterContent»

	public void reset(ActionMapping mapping, HttpServletRequest request) {
		«FOR AssignedField assignedField : form.assignedFields»
			this.«assignedField.fieldName» = «MVCGeneratorGeneratorUtils.getInitialValue(
			MVCGeneratorGeneratorUtils.getSimpleTypeOfAssignement(assignedField))»;
		«ENDFOR»	
	}

	public ActionErrors validate(ActionMapping mapping,
			HttpServletRequest request) {
		ActionErrors errors = new ActionErrors();
		
		«generateConditions(MVCGeneratorGeneratorUtils.getValidator(form))»
		
		return errors;
	}
}
		'''

		for (AssignedField assignedField : form.assignedFields) {

			g.addLineToResourcesContentFile(
				form.name + "." + assignedField.fieldName + ".error.required= " + form.name + "'s " +
					assignedField.fieldName + " is required");
		}

		fsa.generateFile(
			modelMVCContainer.name + "Struts" + StrutsGenerator.actionFormPath + form.name + "ValidationForm.java",
			validationFormContent);

	}

	private def CharSequence generateConditions(FormValidation fv) {
		
		//le prefix de toutes les string erreurs dans le fichier Ressource.properties
		var String prefix= "";
		var condNumber = 1;
		prefix = prefix + MVCGeneratorGeneratorUtils.findContainer(fv, Controller).controlledView.name+".";
		prefix = prefix + MVCGeneratorGeneratorUtils.findContainer(fv, FormValidation).validatedFormName;
		
		
		var CharSequence result = '''
				«IF fv.conditions.length > 0»
				{
					Boolean success = true;
					
					«FOR Condition condition : fv.conditions»
						success = success && («generate(condition.condValue)»);
						
						if(success == false){
							errors.add(ActionMessages.GLOBAL_MESSAGE, "«prefix.toFirstLower».cond«condNumber».error");
						}
						«IF condition.errorDescription != null»
						«g.addLineToResourcesContentFile(prefix.toFirstLower+".cond"+condNumber+".error=\""+condition.errorDescription+"\"")»
						«ELSE»
						«g.addLineToResourcesContentFile(prefix.toFirstLower+".cond"+condNumber+".error=\"An error occur.\"")»
						«ENDIF»
						«MVCGeneratorGeneratorUtils.toVoidExpr(condNumber = condNumber + 1)»
					«ENDFOR»
				}
				«ENDIF»
		'''

		return result;
	}

	private def CharSequence generate(Expression expression) {
		var CharSequence result = ''''''

		if (expression instanceof BooleanExpression) {
			result = generate(expression as BooleanExpression);
		} else if (expression instanceof ArithmeticExpression) {
			result = generate(expression as ArithmeticExpression);
		} else {
			result = '''@Auto_Generated: «expression.getClass.name» is not a handled expression.'''
		}
	}

	private def CharSequence generate(BooleanExpression booleanExpression) {
		var CharSequence result = ''''''

		if (booleanExpression.op1 instanceof BooleanVariable) {
			result = generate(booleanExpression.op1 as BooleanVariable);
		} else if (booleanExpression.op1 instanceof BooleanPrimitive) {
			result = generate(booleanExpression.op1 as BooleanPrimitive);
		} else {
			result = '''@AutoGenerated_Error: «booleanExpression.op1.getClass.name» is not a handled expression.''';
		}

		if (booleanExpression.symbol != null) {
			result = result + ''' «booleanExpression.symbol» '''

			if (booleanExpression.op2 instanceof BooleanVariable) {
				result = result + '''«generate(booleanExpression.op2 as BooleanVariable)»''';
			} else if (booleanExpression.op2 instanceof BooleanPrimitive) {
				result = result + '''«generate(booleanExpression.op2 as BooleanPrimitive)»''';
			} else if (booleanExpression.op2 instanceof ParenthesizedBooleanExpression) {
				result = result + '''«generate(booleanExpression.op2 as ParenthesizedBooleanExpression)»''';
			} else {
				result = '''@AutoGenerated_Error: «booleanExpression.op2.getClass.name» is not a handled expression.''';
			}
		}

		return result;
	}

	private def CharSequence generate(ArithmeticExpression arithmeticExpression) {
		var CharSequence result = ''''''

		if (arithmeticExpression.op1 instanceof ArithmeticVariable) {
			result = generate(arithmeticExpression.op1 as ArithmeticVariable);
		} else if (arithmeticExpression.op1 instanceof ArithmeticPrimitive) {
			result = generate(arithmeticExpression.op1 as ArithmeticPrimitive);
		} else if (arithmeticExpression.op1 instanceof StringLengthExpression) {
			result = generate(arithmeticExpression.op1 as StringLengthExpression);
		} else {
			result = '''@AutoGenerated_Error: «arithmeticExpression.op1.getClass.name» is not a handled expression.''';
		}

		if (arithmeticExpression.symbol != null) {
			result = result + ''' «arithmeticExpression.symbol» '''

			if (arithmeticExpression.op2 instanceof ArithmeticVariable) {
				result = result + '''«generate(arithmeticExpression.op2 as ArithmeticVariable)»''';
			} else if (arithmeticExpression.op2 instanceof ArithmeticPrimitive) {
				result = result + '''«generate(arithmeticExpression.op2 as ArithmeticPrimitive)»''';
			} else if (arithmeticExpression.op1 instanceof StringLengthExpression) {
				result = result +  '''«generate(arithmeticExpression.op1 as StringLengthExpression)»''' ;
			} else if (arithmeticExpression.op2 instanceof ParenthesizedArithmeticExpression) {
				result = result + '''«generate(arithmeticExpression.op2 as ParenthesizedArithmeticExpression)»''';
			} else {
				result = '''@AutoGenerated_Error: «arithmeticExpression.op2.getClass.name» is not a handled expression.''';
			}
		}

		return result;
	}

	private def CharSequence generate(ArithmeticVariable arithmeticVariable) {
		'''«arithmeticVariable.refer»'''
	}

	private def CharSequence generate(StringLengthExpression stringLengthExpression) {
		var result = '''''';

		if (stringLengthExpression.expression instanceof StringExpression) {
			result = '''"«(stringLengthExpression.expression as StringExpression).value»".length()'''
		} else if (stringLengthExpression.expression instanceof ArithmeticVariable) {
			result = '''«(stringLengthExpression.expression as ArithmeticVariable).refer».length()'''
		}

		return result;
	}

	private def CharSequence generate(ArithmeticPrimitive arithmeticPrimitive) {
		if (arithmeticPrimitive instanceof IntegerExpression) {
			'''«(arithmeticPrimitive as IntegerExpression).value»'''
		} else if (arithmeticPrimitive instanceof DoubleExpression) {
			'''«(arithmeticPrimitive as DoubleExpression).value».«(arithmeticPrimitive as DoubleExpression).decimalValue»'''
		} else if (arithmeticPrimitive instanceof StringExpression) {
			'''"«(arithmeticPrimitive as StringExpression).value»"'''
		} else {
			'''@AutoGenerated_Error: «arithmeticPrimitive.class.name» is not a handled ArithmeticPrimitive.'''
		}
	}

	private def CharSequence generate(ParenthesizedArithmeticExpression parenthesizedArithmeticExpression) {
		'''(«generate(parenthesizedArithmeticExpression.expression)»)'''
	}

	private def CharSequence generate(BooleanVariable booleanVariable) {
		'''«booleanVariable.refer»'''
	}

	private def CharSequence generate(BooleanPrimitive booleanPrimitive) {
		'''«booleanPrimitive.value»'''
	}

	private def CharSequence generate(ParenthesizedBooleanExpression parenthesizedBooleanExpression) {
		'''«generate(parenthesizedBooleanExpression.expression)»'''
	}
}
